package canvaswork;

import geomerative.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import processing.core.PApplet;

/**
 *
 * @author jonatanhilden
 */
public class Group extends Grob {

    private List<Grob> children = new ArrayList<Grob>();
    private boolean over = false;
    private boolean selected = false;
    private boolean temporaryselected = false;
    private RGroup groupshp = new RGroup();
    private RShape[] groupSides;
    private RPoint[] groupHandles;
    private int groupSelectedSideNum = -1;
    //private RShape shp;
    float groupscale = 1.0f;

    public Group(Main main, Group parent, int id, int x, int y, int s, int r, int clr) {
        super(main, parent, id, x, y, s, r, clr);

    }

    public List<Grob> getChildren() {
        return new ArrayList<Grob>(children);
    }

    public float getGroupscale() {
        return groupscale;
    }

    public void setGroupscale(float groupscale) {
        this.groupscale = groupscale;
    }

    public void addChild(Grob grob) {
        grob.setParent(this);
        children.add(grob);

    }

    public void removeChild(Grob grob) {
        grob.setParent(null);
        children.remove(grob);
    }

    public void initiateShape() {//called when all children have been added to a group
        for (Grob child : children) {
            child.getShape().translate(-xpos, -ypos);
            groupshp.addElement(child.getShape());
            fillColor = child.fillColor;
            overColor = child.overColor;
            // setting the relativePosition of the children to store the relative relativePosition inside the group
            child.setRelativePosition(0, 0);
            child.translateRelativePosition(child.getXpos()-xpos , child.getYpos()-ypos);

            // inverted verion of relative position
//             child.translateRelativePosition(xpos-child.getXpos() , ypos- child.getYpos());

        }
        setShape(groupshp.toShape());
        if (getShape() != null) {
            Main.println("shape");
        }

    }

    @Override
    void createShp() {
        setShape(new RShape(groupshp.toShape()));
        setSize();
        groupSides = new RShape[getShape().getHandles().length - 1];

    }

    void setSize() {//hackish method for a dummy "size" for a group
        int xmax = main.MAXVALUE;
        int ymax = main.MAXVALUE;
        int xmin = 0;
        int ymin = 0;
        int[] xPositions = new int[children.size()];
        int[] yPositions = new int[children.size()];


        for (Grob child : children) {
            xPositions[children.indexOf(child)] = child.getXpos();
            yPositions[children.indexOf(child)] = child.getXpos();

        }
        xmax = Main.max(xPositions);
        ymax = Main.max(yPositions);
        xmin = Main.min(xPositions);
        ymin = Main.min(yPositions);

        size = ((xmax - xmin) + (ymax - ymin)) / 2;
    }

    @Override
    void setupTransform() {


        getShape().rotate((PApplet.radians(rotation)), getCenter());
        //getShp().rotate((PApplet.radians(newAngleGroup)), rotationAnchorGroup);
        getShape().scale(scale);

        //mirroring
        getShape().scale(mirror, 1, getCenter());
        //positioning
        getShape().translate(xpos, ypos);

        //  Updating positions of children. The relativePosition RPoint contains
        //  the relative relativePosition of the child in the group
        for (Grob child : children) {
            child.setPosition(xpos + Math.round(child.getRelativePosition().x), ypos + Math.round(child.getRelativePosition().y));
        }


        groupHandles = getShape().getHandles();
        for (int i = 0; i < groupHandles.length - 1; i++) {
            RShape s = new RShape();
            s.addMoveTo(groupHandles[i]);
            s.addLineTo(groupHandles[i + 1]);
            groupSides[i] = s;
        }
    }

    public int childCount() {
        return children.size();
    }

    public boolean hasChild(Grob grob) {
        return children.contains(grob);
    }

    public boolean hasChildren() {
        if (children.size() != 0) {
            return true;
        } else {
            return false;
        }
    }

    @Override
    public boolean isGroup() {
        return true;
    }

    @Override
    void draw() {
        //main.noFill();
        main.fill(fillColor);
        //main.text(xpos + " " + ypos, xpos, ypos);

        //main.text(scale, xpos, ypos + size);
        setupTransform();


        main.stroke(fillColor);
        if (isSelected()) {
            main.noFill();
            if (isDraggingGrob()) {
                    main.text(xpos + " " + ypos, xpos, ypos);  // display coordinates
                }

            //main.fill(fillColor);

            main.stroke(fillColor);
        } else if (main.isOver(this) || isTemporarySelected()) {
            main.fill(overColor);
            main.stroke(fillColor);

        } else {
            //main.noFill();
            main.fill(fillColor);
            main.noStroke();
        }

        RG.shape(getShape());
        main.stroke(main.hue(getFillColor() - getFillColor()), 100, ((main.brightness(getFillColor()))));
        if (groupSelectedSideNum != -1 && isSelected()) {
            RG.shape(groupSides[groupSelectedSideNum]);//highlight the selected side
        }
    }

    @Override
    boolean isSelected() {
        selected = false;
        super.isSelected();
        for (Grob child : children) {
            selected |= child.isSelected();
        }
        return selected;

    }

    @Override
    boolean isTemporarySelected() {
        return super.isTemporarySelected();
    }

    @Override
    public int selectSide(int accuracy) {
        float[] distances;
        distances = new float[groupSides.length];
        int s = -1; // side number
        for (int i = 0; i < groupSides.length; i++) {
            if (groupSides[i] != null) {//   calculate the distance between a point(mouse) and a line in sides;
                distances[i] = main.distanceToInfiniteLine(main.mouseX, main.mouseY, (int) (groupSides[i].getHandles()[0].x),
                        (int) (groupSides[i].getHandles()[0].y), (int) (groupSides[i].getHandles()[1].x), (int) (groupSides[i].getHandles()[1].y));
            }
            float dmin = Main.min(distances);
            // getting out the index of the minimum value for choosing the right side
            for (int j = 0; j < distances.length; j++) {
                if (dmin == distances[j] && dmin< accuracy) {
                    groupSelectedSideNum = j;
                }
            }
        }
        return groupSelectedSideNum;
    }

    @Override
    public RShape getSide(int s) {
if (s <= groupSides.length - 1 && s != -1) {
            return groupSides[s];
        } else {
            return groupSides[0];
        }

    }

    @Override
    public RShape[] getSides() {
        return groupSides;
    }

    @Override
    public RPoint getHandle(int h) {
if (h <= groupHandles.length - 1 && h != -1) {
            return groupHandles[h];
        } else {
            return groupHandles[0];
        }    }

    @Override
    public RPoint[] getHandles() {
        return groupHandles;
    }

    @Override
    public int getFillColor() {
        for (Grob child : children) {
            fillColor = child.getFillColor();
        }
        return fillColor;
    }

    @Override
    public void setFillColor(float h, float s, float b) {
        for (Grob child : children) {
            child.setFillColor(h, s, b);
        }
    }

    @Override
    public Group copyGrob(Group newParent, int x, int y, int xx, int yy) {
        //returns a copy of the current grob at x, y -min_X, min_y
        //to retain relative relativePosition if multiple grobs are selected
        Random random = new Random();
        int r = random.nextInt(10) + 1;

        Group group = new Group(main, newParent, object_type, ((x / main.gridSize) * main.gridSize) + xpos - xx,
                ((y / main.gridSize) * main.gridSize) + ypos - yy, size, rotation, fillColor);

        for (Grob child : children) {
            group.addChild(child.copyGrob(group, object_type, ((x / main.gridSize) * main.gridSize) + xpos - xx,
                    ((y / main.gridSize) * main.gridSize) + ypos - yy, size));
        }
        group.groupshp = (groupshp);
        return group;

    }
}
